package com.piggy.logi.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.piggy.common.core.constant.SecurityConstants;
import com.piggy.common.core.enums.CacheKeyEnums;
import com.piggy.common.core.exception.GlobalException;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.common.redis.cache.CacheUtils;
import com.piggy.common.satoken.utils.SecurityUtils;
import com.piggy.logi.sys.api.utils.ZhongYouApiUtil;
import com.piggy.logi.sys.api.vo.LogiSysDeptExtVo;
import com.piggy.logi.sys.bo.*;
import com.piggy.logi.sys.domain.*;
import com.piggy.logi.sys.enums.BizNoPrefixEnum;
import com.piggy.logi.sys.enums.GoodOrderStatusEnum;
import com.piggy.logi.sys.enums.ScheduleStatusEnum;
import com.piggy.logi.sys.enums.WaybillStatusEnum;
import com.piggy.logi.sys.mapper.LogiScheduleMapper;
import com.piggy.logi.sys.mapper.LogiWaybillMapper;
import com.piggy.logi.sys.service.*;
import com.piggy.logi.sys.vo.LogiCarrierCarExtVo;
import com.piggy.logi.sys.vo.LogiCarrierDriverExtVo;
import com.piggy.logi.sys.vo.LogiScheduleExtVo;
import com.piggy.logi.sys.vo.LogiScheduleVo;
import com.piggy.sys.api.RemoteDistrictService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 调度车次信息Service业务层处理
 *
 * @author piggy
 * @date 2023-09-06
 */
@Slf4j
@Service
public class LogiScheduleServiceImpl extends ServiceImpl<LogiScheduleMapper, LogiSchedule> implements ILogiScheduleService {

    @Resource
    private ILogiCarrierDriverService driverService;

    @Resource
    private ILogiCarrierCarService carService;

    @Resource
    private ILogiLineService lineService;

    @Resource
    private ILogiCarrierService carrierService;

    @Resource
    private ILogiWaybillService logiWaybillService;

    @Resource
    private ILogiWaybillOrderRelateService waybillOrderRelateService;

    @Resource
    private ILogiScheduleLogService logiScheduleLogService;

    @Resource
    private ILogiScheduleFeeService feeService;

    @Resource
    private ILogiSysBaseConfigService logiSysBaseConfigService;

    @Resource
    private ILogiSysDeptService deptService;

    @Resource
    private RemoteDistrictService districtService;

    @Resource
    private ILogiWaybillOrderRelateService logiWaybillOrderRelateService;

    @Resource
    private ILogiGoodOrderService logiGoodOrderService;

    @Resource
    private ILogiWaybillGoodSourceService logiWaybillGoodSourceService;

    @Resource
    private LogiWaybillMapper waybillMapper;

    @Override
    public LogiScheduleExtVo queryById(Long scheduleId) {
        LogiScheduleExtVo vo = getVoById(scheduleId, LogiScheduleExtVo.class);
        if (ObjectUtil.isEmpty(vo)) {
            return vo;
        }

        return fillData(Lists.newArrayList(vo), false).get(0);
    }

    @Override
    public TableDataInfo<LogiScheduleExtVo> queryPageList(LogiScheduleQueryBo bo) {
        bo.setDeptId(SecurityUtils.getDeptId());
        PageInfo<LogiScheduleExtVo> result = startPage(bo).doSelectPageInfo(() -> {
            List<LogiScheduleExtVo> voList = baseMapper.selectSCHList(buildQueryWrapper(bo));
            fillData(voList, false);
        });
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiScheduleExtVo> queryList(LogiScheduleQueryBo bo, boolean ignoreWaybill) {
        bo.setDeptId(SecurityUtils.getDeptId());
        return fillData(baseMapper.selectSCHList(buildQueryWrapper(bo)), ignoreWaybill);
    }

    @Override
    public List<LogiScheduleExtVo> queryList(LogiScheduleQueryBo bo) {
        return queryList(bo, false);
    }

    private QueryWrapper<LogiSchedule> buildQueryWrapper(LogiScheduleQueryBo bo) {
        QueryWrapper<LogiSchedule> lqw = Wrappers.query();
        lqw.eq(bo.getScheduleId() != null, "sch.schedule_id", bo.getScheduleId());
        //lqw.eq(bo.getDeptId() != null, "sch.dept_id", bo.getDeptId());
        lqw.like(StrUtil.isNotBlank(bo.getScheduleNo()), "sch.schedule_no", bo.getScheduleNo());
        lqw.like(StrUtil.isNotBlank(bo.getBusNo()), "sch.bus_no", bo.getBusNo());
        lqw.eq(bo.getWaybillId() != null, "sch.waybill_id", bo.getWaybillId());
        lqw.eq(bo.getLineId() != null, "sch.line_id", bo.getLineId());
        lqw.eq(bo.getDriverId() != null, "sch.driver_id", bo.getDriverId());
        lqw.eq(bo.getCarId() != null, "sch.car_id", bo.getCarId());
        lqw.eq(bo.getFlowStatus() != null, "sch.flow_status", bo.getFlowStatus());
        lqw.apply(ObjectUtil.isAllNotEmpty(bo.getEstDepartTimeStart(), bo.getEstDepartTimeEnd()), "date_format(sch.est_depart_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') ", bo.getEstDepartTimeStart(), bo.getEstDepartTimeEnd());
        lqw.apply(ObjectUtil.isAllNotEmpty(bo.getDepartTimeStart(), bo.getDepartTimeEnd()), "date_format(sch.depart_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') ", bo.getDepartTimeStart(), bo.getDepartTimeEnd());
        lqw.apply(ObjectUtil.isAllNotEmpty(bo.getEstArriveTimeStart(), bo.getEstArriveTimeEnd()), "date_format(sch.est_arrive_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') ", bo.getEstArriveTimeStart(), bo.getEstArriveTimeEnd());
        lqw.apply(ObjectUtil.isAllNotEmpty(bo.getArriveTimeStart(), bo.getArriveTimeEnd()), "date_format(sch.arrive_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') ", bo.getArriveTimeStart(), bo.getArriveTimeEnd());
        lqw.apply(ObjectUtil.isAllNotEmpty(bo.getFinishedTimeStart(), bo.getFinishedTimeEnd()), "date_format(sch.finished_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') ", bo.getFinishedTimeStart(), bo.getFinishedTimeEnd());
        lqw.in(CollUtil.isNotEmpty(bo.getScheduleNos()), "sch.schedule_no", bo.getScheduleNos());
        lqw.in(CollUtil.isNotEmpty(bo.getStatusList()), "sch.flow_status", bo.getStatusList());

        lqw.like(StrUtil.isNotBlank(bo.getOutCode()), "bill.out_code", bo.getOutCode());
        lqw.and(StrUtil.isNotBlank(bo.getCustomerName()), lqw1 -> lqw1.like("c1.customer_name", bo.getCustomerName()).or().like("c2.customer_name", bo.getCustomerName()));
        // 运单增加数据权限处理
        lqw.apply(ObjectUtil.isNotEmpty(bo.getDeptId()), StrUtil.format("sch.dept_id in (SELECT dept_id FROM logi_sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ))", bo.getDeptId(), bo.getDeptId()));
        lqw.orderByAsc("sch.flow_status");
        return lqw;
    }

    private List<LogiScheduleExtVo> fillData(List<LogiScheduleExtVo> recordVos, boolean ignoreWaybill) {
        if (CollUtil.isEmpty(recordVos)) {
            return recordVos;
        }

        // 获取网点数据
        List<Long> deptIds = Lists.newArrayList();
        for (LogiScheduleExtVo item : recordVos) {
            deptIds.add(item.getShipNetId());
            deptIds.add(item.getDeliveryNetId());
        }
        deptIds = deptIds.stream().distinct().collect(Collectors.toList());
        List<LogiSysDeptExtVo> sysDeptExtVos = deptService.selectDeptByIds(deptIds);
        Map<Long, LogiSysDeptExtVo> deptExtVoMap = sysDeptExtVos.stream().collect(Collectors.toMap(LogiSysDeptExtVo::getDeptId, Function.identity()));
        // 获取地址数据
        List<String> districtIds = recordVos.stream().map(item -> item.getShipDistrictId().toString()).distinct().collect(Collectors.toList());
        districtIds.addAll(recordVos.stream().map(item -> item.getDeliveryDistrictId().toString()).distinct().collect(Collectors.toList()));
        districtIds = districtIds.stream().distinct().collect(Collectors.toList());
        Map<String, String> districtNameMap = districtService.getDistrictMap(districtIds, SecurityConstants.INNER).getData();

        return recordVos.stream().peek(vo -> {
            vo.setCarVo(JSON.parseObject(vo.getCarJson(), LogiCarrierCarExtVo.class));
            vo.setDriverVo(JSON.parseObject(vo.getDriverJson(), LogiCarrierDriverExtVo.class));

            /*LogiCarrierCarExtVo carExtVo = carService.queryById(vo.getCarId());
            vo.setCarVo(JSON.parseObject(vo.getCarJson(), LogiCarrierCarExtVo.class));
            if (ObjectUtil.isNotEmpty(carExtVo)) {
                BeanUtil.copyProperties(vo.getCarVo(), carExtVo, CopyOptions.create().ignoreNullValue());
                vo.setCarVo(carExtVo);
            }
            vo.setDriverVo(JSON.parseObject(vo.getDriverJson(), LogiCarrierDriverExtVo.class));
            LogiCarrierDriverExtVo driverExtVo = driverService.queryById(vo.getDriverId());
            if (ObjectUtil.isNotEmpty(driverExtVo)) {
                BeanUtil.copyProperties(vo.getDriverVo(), driverExtVo, CopyOptions.create().ignoreNullValue());
                vo.setDriverVo(driverExtVo);
            }*/
            vo.setLineVo(lineService.queryById(vo.getLineId()));
            vo.setCarrierVo(carrierService.queryById(vo.getCarrierId()));
            vo.setFeeList(feeService.queryList(new LogiScheduleFeeQueryBo().setScheduleId(vo.getScheduleId())));
            if (StrUtil.isNotBlank(vo.getScheduleNo()) && !ignoreWaybill) {
                LogiWaybillQueryBo queryBo = new LogiWaybillQueryBo().setScheduleNo(vo.getScheduleNo());
                queryBo.setDeptId(SecurityUtils.getDeptId());
                vo.setWaybillList(logiWaybillService.queryList(queryBo));
            }
            Optional.ofNullable(vo.getShipDistrictId()).ifPresent(item -> vo.setShipDistrictName(districtNameMap.get(item.toString())));
            Optional.ofNullable(vo.getDeliveryDistrictId()).ifPresent(item -> vo.setDeliveryDistrictName(districtNameMap.get(item.toString())));
            Optional.ofNullable(vo.getShipNetId()).ifPresent(item -> vo.setShipNetName(ObjectUtil.defaultIfNull(deptExtVoMap.get(vo.getShipNetId()), new LogiSysDeptExtVo()).getDeptName()));
            Optional.ofNullable(vo.getDeliveryNetId()).ifPresent(item -> vo.setDeliveryNetName(ObjectUtil.defaultIfNull(deptExtVoMap.get(vo.getDeliveryNetId()), new LogiSysDeptExtVo()).getDeptName()));
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LogiScheduleExtVo save(LogiScheduleExtEditBo bo) {
        bo.setDeptId(SecurityUtils.getDeptId());
        String date = DateUtil.format(new Date(), "yyyyMMdd");

//        String key = CacheKeyEnums.LogiScheduleNo.getKey(date);
//        if (!CacheUtils.hasKey(key)) {
//            CacheUtils.cache(0, key, 2L, TimeUnit.DAYS);
//        }
//        Long no = CacheUtils.incrBy(key);
//        bo.setScheduleNo(String.format("%s%s%06d", BizNoPrefixEnum.SCHEDULE_NO.getCode(), date, no));
        bo.setScheduleNo(logiSysBaseConfigService.getScheduleNo(bo.getDeptId()));

        String key = CacheKeyEnums.LogiBusNo.getKey(date);
        if (!CacheUtils.hasKey(key)) {
            CacheUtils.cache(0, key, 2L, TimeUnit.DAYS);
        }
        Long no = CacheUtils.incrBy(key);
        bo.setBusNo(String.format("%s%s%06d", BizNoPrefixEnum.BUS_NO.getCode(), date, no));

        bo.setFlowStatus(ScheduleStatusEnum.SCHEDULED.getCode());
        LogiSchedule add = BeanUtil.toBean(bo, LogiSchedule.class);
        add.setDriverId(bo.getDriverJson().getDriverId());
        add.setCarId(bo.getCarJson().getCarId());

        add.setDriverJson(JSON.toJSONString(bo.getDriverJson()));
        add.setCarJson(JSON.toJSONString(bo.getCarJson()));

        LogiCarrierCarExtVo carExtVo = carService.queryById(add.getCarId());
        if (ObjectUtil.isNotEmpty(carExtVo)) {
            BeanUtil.copyProperties(bo.getCarJson(), carExtVo, CopyOptions.create().ignoreNullValue());
            add.setCarJson(JSON.toJSONString(carExtVo));
        }
        LogiCarrierDriverExtVo driverExtVo = driverService.queryById(add.getDriverId());
        if (ObjectUtil.isNotEmpty(driverExtVo)) {
            BeanUtil.copyProperties(add.getDriverJson(), driverExtVo, CopyOptions.create().ignoreNullValue());
            add.setDriverJson(JSON.toJSONString(driverExtVo));
        }

        add.setCreateBy(SecurityUtils.getPhone());
        add.setCreateTime(new Date());
        add.setCanDepart(1);

        // 判断是否关联线上订单，如果有则不能直接发车，需等待确认
        List<LogiWaybillOrderRelate> waybillOrderRelateList;
        if (CollUtil.isNotEmpty(bo.getWaybillIds())) {
            waybillOrderRelateList = logiWaybillOrderRelateService.listByWaybillIds(bo.getWaybillIds());
//            long count = waybillOrderRelateList.stream().filter(a -> a.getGoodOrderType() == 1).count();
//            if (count > 0) {
//                add.setCanDepart(0);
//            }
        } else {
            waybillOrderRelateList = CollUtil.newArrayList();
        }

        save(add);

        if (CollUtil.isNotEmpty(bo.getFeeList())) {
            bo.getFeeList().stream().peek(Any -> {
                Any.setScheduleId(add.getScheduleId());
                Any.setLineId(bo.getLineId());
            }).collect(Collectors.toList());
            feeService.batchByAddBo(bo.getFeeList());
        }

        if (CollUtil.isNotEmpty(bo.getWaybillIds())) {
            LambdaUpdateWrapper<LogiWaybill> updateWrapper = Wrappers.lambdaUpdate();
            bo.getWaybillIds().add(0L);
            updateWrapper.set(LogiWaybill::getScheduleNo, bo.getScheduleNo())
                    /*.set(LogiWaybill::getScheduleStatus, ObjectUtil.defaultIfNull(bo.getFlowStatus(),0L))
                    .set(LogiWaybill::getStatus, WaybillStatusEnum.SCHEDULED.getCode())*/
                    .in(LogiWaybill::getWaybillId, bo.getWaybillIds());
            logiWaybillService.update(updateWrapper);
            logiWaybillService.checkAndUpdateStatus(bo.getScheduleNo(), WaybillStatusEnum.SCHEDULED);
        }

        // 通知众油平台
        for (LogiWaybillOrderRelate logiWaybillOrderRelate : waybillOrderRelateList) {
            if (logiWaybillOrderRelate.getGoodOrderType() == 1) {
                LogiGoodOrder goodOrder = logiGoodOrderService.getById(logiWaybillOrderRelate.getGoodOrderId());
                List<LogiWaybillGoodSource> waybillGoodSources = logiWaybillGoodSourceService.getByWaybillIds(Collections.singletonList(logiWaybillOrderRelate.getWaybillId()));
                BigDecimal count = waybillGoodSources.stream().map(a -> StrUtil.isNotBlank(a.getWeight()) ? new BigDecimal(a.getWeight()) : BigDecimal.ZERO).reduce(BigDecimal.ZERO, BigDecimal::add);
                ZhongYouApiUtil.orderCallBack(goodOrder.getPickupOrderNo(), logiWaybillOrderRelate.getWaybillId().toString(),
                        ObjectUtil.isNotNull(driverExtVo) ? driverExtVo.getDriverName() : "", ObjectUtil.isNotNull(driverExtVo) ? driverExtVo.getPhoneNumber() : "",
                        ObjectUtil.isNotNull(driverExtVo) ? driverExtVo.getIdCardNo() : "", ObjectUtil.isNotNull(carExtVo) ? carExtVo.getLicensePlate() : "", count.floatValue(),
                        DateUtil.formatDateTime(add.getCreateTime()), bo.getEscortor(), bo.getEscortorIdcard(), bo.getEscortorPhone());
            }
        }

        return queryById(add.getScheduleId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LogiScheduleExtVo updateByEditBo(LogiScheduleExtEditBo bo) {
        LogiSchedule update = BeanUtil.toBean(bo, LogiSchedule.class);
        update.setDriverJson(JSON.toJSONString(bo.getDriverJson()));
        update.setCarJson(JSON.toJSONString(bo.getCarJson()));

        LogiCarrierCarExtVo carExtVo = carService.queryById(update.getCarId());
        if (ObjectUtil.isNotEmpty(carExtVo)) {
            BeanUtil.copyProperties(bo.getCarJson(), carExtVo, CopyOptions.create().ignoreNullValue());
            update.setCarJson(JSON.toJSONString(carExtVo));
        }

        LogiCarrierDriverExtVo driverExtVo = driverService.queryById(update.getDriverId());
        if (ObjectUtil.isNotEmpty(driverExtVo)) {
            BeanUtil.copyProperties(update.getDriverJson(), driverExtVo, CopyOptions.create().ignoreNullValue());
            update.setDriverJson(JSON.toJSONString(driverExtVo));
        }

        update.setUpdateBy(SecurityUtils.getPhone());
        update.setUpdateTime(new Date());
        updateById(update);
        update = getById(update.getScheduleId());

        if (CollUtil.isNotEmpty(bo.getFeeList())) {
            LogiSchedule finalUpdate = update;
            bo.getFeeList().stream().peek(Any -> {
                Any.setScheduleId(finalUpdate.getScheduleId());
                Any.setLineId(bo.getLineId());
            }).collect(Collectors.toList());
            feeService.batchByUpdateBo(bo.getFeeList());
        }

        //logiWaybillService.updateScheduleStatus(update.getScheduleNo(), ObjectUtil.defaultIfNull(bo.getFlowStatus(),0));
        if (CollUtil.isNotEmpty(bo.getWaybillIds())) {
            LambdaUpdateWrapper<LogiWaybill> updateWrapper = Wrappers.lambdaUpdate();
            bo.getWaybillIds().add(0L);
            updateWrapper.set(LogiWaybill::getScheduleNo, bo.getScheduleNo())
                    .set(LogiWaybill::getScheduleStatus, update.getFlowStatus())
                    .in(LogiWaybill::getWaybillId, bo.getWaybillIds());
            logiWaybillService.update(updateWrapper);
        }
        if (ObjectUtil.isEmpty(bo.getFlowStatus()) || bo.getFlowStatus().equals(update.getFlowStatus())) {
            return queryById(update.getScheduleId());
        }
        logiWaybillService.updateScheduleStatus(update.getScheduleNo(), update.getFlowStatus());

        return queryById(update.getScheduleId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return removeByIds(ids);
    }

    @Override
    public TableDataInfo<LogiScheduleExtVo> dispatchCarList(OperationDispatchCarQueryBo queryBo) {
        if (ObjectUtil.isNotEmpty(queryBo.getWaybillId())) {
            LogiWaybill waybill = waybillMapper.selectById(queryBo.getWaybillId());
            if (ObjectUtil.isNotEmpty(waybill)) {
                queryBo.setScheduleNos(Lists.newArrayList(StrUtil.blankToDefault(waybill.getScheduleNo(), "0")));
            }
        }
        PageInfo<LogiScheduleExtVo> result = startPage(queryBo).doSelectPageInfo(() -> {
            List<LogiScheduleExtVo> voList = baseMapper.selectSCHList(buildDispatchCarList(queryBo));
            fillData(voList, false);
        });
        return PageUtils.buildDataInfo(result);
    }

    private QueryWrapper<LogiSchedule> buildDispatchCarList(OperationDispatchCarQueryBo queryBo) {
        QueryWrapper<LogiSchedule> lqw = buildQueryWrapper(queryBo);

        if (queryBo.getFlowStatus() == null && ObjectUtil.defaultIfNull(queryBo.getDispatchType(), -1) == 0) {
            lqw.in("sch.flow_status", ScheduleStatusEnum.getDispatchCarList0());
        } else if (queryBo.getFlowStatus() == null && ObjectUtil.defaultIfNull(queryBo.getDispatchType(), -1) == 1) {
            lqw.in("sch.flow_status", ScheduleStatusEnum.getDispatchCarList1());
        }
        lqw.in(CollUtil.isNotEmpty(queryBo.getScheduleNos()), "sch.schedule_no", queryBo.getScheduleNos());
        lqw.in(CollUtil.isNotEmpty(queryBo.getScheduleList()), "sch.flow_status", queryBo.getScheduleList());
        lqw.like(StrUtil.isNotBlank(queryBo.getLicensePlate()), "sch.car_json", queryBo.getLicensePlate());
        lqw.like(StrUtil.isNotBlank(queryBo.getDriverName()), "sch.driver_json", queryBo.getDriverName());
        lqw.like(StrUtil.isNotBlank(queryBo.getPhoneNumber()), "sch.driver_json", queryBo.getPhoneNumber());
        lqw.apply(ObjectUtil.isAllNotEmpty(queryBo.getCreateTimeStart(), queryBo.getCreateTimeEnd()), "date_format(sch.create_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') ", queryBo.getCreateTimeStart(), queryBo.getCreateTimeEnd());
        lqw.orderByAsc("sch.flow_status");
        return lqw;
    }

    @Override
    public List<LogiScheduleVo> getByCarIds(List<Long> carIds) {
        if (CollUtil.isEmpty(carIds)) {
            return Lists.newArrayList();
        }
        return BeanUtil.copyToList(baseMapper.selectByCarIds(carIds), LogiScheduleVo.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void depart(String scheduleNo) {
        LogiSchedule logiSchedule = baseMapper.selectByScheduleNo(scheduleNo);
        if (logiSchedule == null || logiSchedule.getFlowStatus() != ScheduleStatusEnum.PICKUPING.getCode()) {
            throw new GlobalException(String.format("车次目前在[%s]，不能发车操作!", ScheduleStatusEnum.get(logiSchedule.getFlowStatus()).getInfo()));
        }
        // 是否可发车：0.不能 1.能
        if (logiSchedule.getCanDepart() == 0) {
            throw new GlobalException("车次含有线上订单，需要确认才能发车!");
        }
        // 判断关联的线上订单是否已取消
        List<LogiWaybill> waybillList = waybillMapper.selectByScheduleNo(scheduleNo);
        List<Long> waybillIdList = CollUtil.newArrayList();
        List<String> msgList = CollUtil.newArrayList();
        for (LogiWaybill logiWaybill : waybillList) {
            waybillIdList.add(logiWaybill.getWaybillId());
            List<LogiWaybillOrderRelate> waybillOrderRelateList = logiWaybillOrderRelateService.listByWaybillIds(CollUtil.newArrayList(logiWaybill.getWaybillId()));
            List<Long> goodOrderIds = waybillOrderRelateList.stream().filter(a -> a.getGoodOrderType() == 1).map(LogiWaybillOrderRelate::getGoodOrderId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(goodOrderIds)) {
                List<LogiGoodOrder> logiGoodOrders = logiGoodOrderService.listByIds(goodOrderIds);
                if (CollUtil.isNotEmpty(logiGoodOrders)) {
                    for (LogiGoodOrder logiGoodOrder : logiGoodOrders) {
                        if (logiGoodOrder.getStatus() == GoodOrderStatusEnum.CANCEL.getCode()) {
                            msgList.add(String.format("运单【%s】关联的线上订单【%s】已取消", logiWaybill.getOutCode(), logiGoodOrder.getOrderCode()));
                        }
                    }
                }
            }
        }
        if (CollUtil.isNotEmpty(msgList)) {
            throw new GlobalException("发车失败：" + String.join("，", msgList));
        }

        LogiSchedule update = new LogiSchedule();
        update.setScheduleId(logiSchedule.getScheduleId());
        update.setFlowStatus(ScheduleStatusEnum.DEPARTED.getCode());
        if (StrUtil.isBlank(logiSchedule.getBusNo()) && logiSchedule.getFlowStatus() == ScheduleStatusEnum.DEPARTED.getCode()) {
            String date = DateUtil.format(new Date(), "yyyyMMdd");
            String key = CacheKeyEnums.LogiBusNo.getKey(date);
            if (!CacheUtils.hasKey(key)) {
                CacheUtils.cache(0, key, 2L, TimeUnit.DAYS);
            }
            Long no = CacheUtils.incrBy(key);
            update.setBusNo(String.format("%s%s%06d", BizNoPrefixEnum.BUS_NO.getCode(), date, no));
        }
        update.setDepartTime(new Date());
        update.setUpdateTime(new Date());
        update.setUpdateBy(SecurityUtils.getPhone());
        updateById(update);

        logiWaybillService.depart(scheduleNo);
        logiScheduleLogService.addLog(logiSchedule.getScheduleId(), ScheduleStatusEnum.DEPARTED.getCode());
        // 运单调度状态处理
        logiWaybillService.updateScheduleStatus(scheduleNo, ScheduleStatusEnum.DEPARTED.getCode());

        // 通知众油平台
        List<LogiWaybillOrderRelate> waybillOrderRelateList = waybillOrderRelateService.listByWaybillIds(waybillIdList);
        for (LogiWaybillOrderRelate logiWaybillOrderRelate : waybillOrderRelateList) {
            if (logiWaybillOrderRelate.getGoodOrderType() == 1) {
                LogiGoodOrder goodOrder = logiGoodOrderService.getById(logiWaybillOrderRelate.getGoodOrderId());
                ZhongYouApiUtil.orderStateChange(goodOrder.getPickupOrderNo(), logiWaybillOrderRelate.getWaybillId().toString(), DateUtil.formatDateTime(update.getDepartTime()), 1);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelDepart(String scheduleNo) {
        LogiSchedule logiSchedule = baseMapper.selectByScheduleNo(scheduleNo);
        if (logiSchedule == null || logiSchedule.getFlowStatus() != ScheduleStatusEnum.DEPARTED.getCode()) {
            throw new GlobalException(String.format("车次目前在[%s]，不能取消发车!", ScheduleStatusEnum.get(logiSchedule.getFlowStatus()).getInfo()));
        }
        // 发车时间超过1小时，不能取消
        if (logiSchedule.getDepartTime().before(DateUtil.offsetHour(new Date(), -1).toJdkDate())) {
            throw new GlobalException("发车一小时后不可取消");
        }
        LogiSchedule update = new LogiSchedule();
        update.setScheduleId(logiSchedule.getScheduleId());
        update.setFlowStatus(ScheduleStatusEnum.PICKUPING.getCode());
        update.setDepartTime(null);
        update.setUpdateTime(new Date());
        update.setUpdateBy(SecurityUtils.getPhone());
        updateById(update);

        logiWaybillService.cancelDepart(scheduleNo);
        logiScheduleLogService.addLog(logiSchedule.getScheduleId(), ScheduleStatusEnum.PICKUPING.getCode());
        // 运单调度状态处理
        logiWaybillService.updateScheduleStatus(scheduleNo, ScheduleStatusEnum.PICKUPING.getCode());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void arrived(String scheduleNo) {
        LogiSchedule logiSchedule = baseMapper.selectByScheduleNo(scheduleNo);
        if (logiSchedule == null || logiSchedule.getFlowStatus() != ScheduleStatusEnum.DEPARTED.getCode()) {
            throw new GlobalException(String.format("车次目前在[%s]，不能到达操作!", ScheduleStatusEnum.get(logiSchedule.getFlowStatus()).getInfo()));
        }
        LogiSchedule update = new LogiSchedule();
        update.setScheduleId(logiSchedule.getScheduleId());
        update.setFlowStatus(ScheduleStatusEnum.ARRIVED.getCode());
        update.setArriveTime(new Date());
        update.setUpdateTime(new Date());
        update.setUpdateBy(SecurityUtils.getPhone());
        updateById(update);

        logiWaybillService.arrived(scheduleNo);
        logiScheduleLogService.addLog(logiSchedule.getScheduleId(), ScheduleStatusEnum.ARRIVED.getCode());
        // 运单调度状态处理
        logiWaybillService.updateScheduleStatus(scheduleNo, ScheduleStatusEnum.ARRIVED.getCode());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelArrived(String scheduleNo) {
        LogiSchedule logiSchedule = baseMapper.selectByScheduleNo(scheduleNo);
        if (logiSchedule == null || logiSchedule.getFlowStatus() != ScheduleStatusEnum.ARRIVED.getCode()) {
            throw new GlobalException(String.format("车次目前在[%s]，不能取消到达!", ScheduleStatusEnum.get(logiSchedule.getFlowStatus()).getInfo()));
        }
        LogiSchedule update = new LogiSchedule();
        update.setScheduleId(logiSchedule.getScheduleId());
        update.setFlowStatus(ScheduleStatusEnum.DEPARTED.getCode());
        update.setArriveTime(null);
        update.setUpdateTime(new Date());
        update.setUpdateBy(SecurityUtils.getPhone());
        updateById(update);

        logiWaybillService.cancelArrived(scheduleNo);
        logiScheduleLogService.addLog(logiSchedule.getScheduleId(), ScheduleStatusEnum.DEPARTED.getCode());
        // 运单调度状态处理
        logiWaybillService.updateScheduleStatus(scheduleNo, ScheduleStatusEnum.DEPARTED.getCode());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completed(String scheduleNo) {
        LogiSchedule logiSchedule = baseMapper.selectByScheduleNo(scheduleNo);
        if (logiSchedule == null || logiSchedule.getFlowStatus() != ScheduleStatusEnum.ARRIVED.getCode()) {
            throw new GlobalException(String.format("车次目前在[%s]，不能完成操作!", ScheduleStatusEnum.get(logiSchedule.getFlowStatus()).getInfo()));
        }
        LogiSchedule update = new LogiSchedule();
        update.setScheduleId(logiSchedule.getScheduleId());
        update.setFlowStatus(ScheduleStatusEnum.FINSHED.getCode());
        update.setFinishedTime(new Date());
        update.setUpdateTime(new Date());
        update.setUpdateBy(SecurityUtils.getPhone());
        updateById(update);

        logiWaybillService.checkWaybillSign(scheduleNo);
        logiScheduleLogService.addLog(logiSchedule.getScheduleId(), ScheduleStatusEnum.FINSHED.getCode());
        // 运单调度状态处理
        logiWaybillService.updateScheduleStatus(scheduleNo, ScheduleStatusEnum.FINSHED.getCode());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelScheduled(String scheduleNo) {
        LogiSchedule logiSchedule = baseMapper.selectByScheduleNo(scheduleNo);
        if (logiSchedule == null || logiSchedule.getFlowStatus() != ScheduleStatusEnum.SCHEDULED.getCode()) {
            throw new GlobalException(String.format("车次目前在[%s]，不能取消调度!", ScheduleStatusEnum.get(logiSchedule.getFlowStatus()).getInfo()));
        }
        LogiSchedule update = new LogiSchedule();
        update.setScheduleId(logiSchedule.getScheduleId());
        update.setFlowStatus(ScheduleStatusEnum.CANCEL_SCHEDULE.getCode());
        update.setFinishedTime(new Date());
        update.setUpdateTime(new Date());
        update.setUpdateBy(SecurityUtils.getPhone());
        updateById(update);

        //logiWaybillService.completed(scheduleNo);
        logiScheduleLogService.addLog(logiSchedule.getScheduleId(), ScheduleStatusEnum.CANCEL_SCHEDULE.getCode());
        // 运单调度状态处理
        logiWaybillService.updateScheduleStatus(scheduleNo, ScheduleStatusEnum.CANCEL_SCHEDULE.getCode());
    }

    @Override
    public TableDataInfo<LogiScheduleExtVo> scheduleCarLoad(OperationDispatchQueryBo queryBo) {
        return null;
    }

}
